package top.yaofengqiao.springcloudsimple.web.starter.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import top.yaofengqiao.springcloudsimple.common.constant.ResponseCode;
import top.yaofengqiao.springcloudsimple.common.util.AppException;
import top.yaofengqiao.springcloudsimple.common.util.R;

/**
 * @author yfq
 * @date 2024/6/4 16:15
 * @description 全局异常处理
 */
@Slf4j
@RestController
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理业务异常
     */
    @ExceptionHandler(AppException.class)
    public R<String> handleAppException(AppException exception) {
        return R.fail(exception.getCode(), exception.getInfo());
    }

    /**
     * 处理参数校验异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
        BindingResult bindingResult = exception.getBindingResult();
        ObjectError error = bindingResult.getAllErrors().stream().findFirst().orElse(null);
        String msg = error != null ? error.getDefaultMessage() : ResponseCode.UN_ERROR.getInfo();

        return R.fail(ResponseCode.ILLEGAL_PARAMETER.getCode(), msg);
    }

    /**
     * 处理认证异常
     */
    @ExceptionHandler(AuthenticationException.class)
    public R<String> handleAuthenticationException(AuthenticationException exception) {
        // 用户名或密码错误(认证错误)
        if (exception instanceof BadCredentialsException) return R.fail(ResponseCode.USER_OR_PWD_ERROR);

        // 账户被锁定
        if (exception instanceof LockedException) return R.fail(ResponseCode.USER_LOCK);

        return R.fail(ResponseCode.USER_OR_PWD_ERROR);
    }

    /**
     * 处理授权异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    public R<String> handleAuthenticationException(AccessDeniedException exception) {
        return R.fail(ResponseCode.UNAUTHORIZED);
    }

    /**
     * 未知异常
     */
    @ExceptionHandler(Throwable.class)
    public R<String> handleException(Throwable exception) {
        log.error("Exception处理：", exception);

        return R.fail(ResponseCode.UN_ERROR);
    }

}
